/***********************************************************************
    filename:   CEGUIFalTextComponent.cpp
    created:    Sun Jun 19 2005
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/

#include "renderers/TextComponent.h"
#include "hgeFontManager.h"
#include "hgeExceptions.h"
#include "hgePropertyHelper.h"
#include "hgeFont.h"
#include "hgeGuiRenderedString.h"
#include <iostream>


TextComponent::TextComponent() :
    d_formattedRenderedString(new LeftAlignedRenderedString(d_renderedString)),
    d_lastHorzFormatting(HTF_LEFT_ALIGNED),
    d_vertFormatting(VTF_TOP_ALIGNED),
    d_horzFormatting(HTF_LEFT_ALIGNED)
{}

const String& TextComponent::getText() const
{
    return d_textLogical;
}

void TextComponent::setText(const String& text)
{
    d_textLogical = text;
}

const String& TextComponent::getFont() const
{
    return d_font;
}

void TextComponent::setFont(const String& font)
{
    d_font = font;
}

VerticalTextFormatting TextComponent::getVerticalFormatting() const
{
    return d_vertFormatting;
}

void TextComponent::setVerticalFormatting(VerticalTextFormatting fmt)
{
    d_vertFormatting = fmt;
}

HorizontalTextFormatting TextComponent::getHorizontalFormatting() const
{
    return d_horzFormatting;
}

void TextComponent::setHorizontalFormatting(HorizontalTextFormatting fmt)
{
    d_horzFormatting = fmt;
}

void TextComponent::setupStringFormatter(const Window& window,
                                         const RenderedString& rendered_string) const
{
    const HorizontalTextFormatting horzFormatting = d_horzFormatPropertyName.empty() ? d_horzFormatting :
        PropertyHelper::stringToHorzTextFormat(window.getProperty(d_horzFormatPropertyName));

    // no formatting change
    if (horzFormatting == d_lastHorzFormatting)
    {
        d_formattedRenderedString->setRenderedString(rendered_string);
        return;
    }

    d_lastHorzFormatting = horzFormatting;

    switch(horzFormatting)
    {
    case HTF_LEFT_ALIGNED:
        d_formattedRenderedString =
            new LeftAlignedRenderedString(rendered_string);
        break;

    case HTF_CENTRE_ALIGNED:
        d_formattedRenderedString =
            new CentredRenderedString(rendered_string);
        break;

    case HTF_RIGHT_ALIGNED:
        d_formattedRenderedString =
            new RightAlignedRenderedString(rendered_string);
        break;

    case HTF_JUSTIFIED:
        d_formattedRenderedString =
            new JustifiedRenderedString(rendered_string);
        break;

    //case HTF_WORDWRAP_LEFT_ALIGNED:
    //    d_formattedRenderedString =
    //        new RenderedStringWordWrapper
    //            <LeftAlignedRenderedString>(rendered_string);
    //    break;

    //case HTF_WORDWRAP_CENTRE_ALIGNED:
    //    d_formattedRenderedString =
    //        new RenderedStringWordWrapper
    //            <CentredRenderedString>(rendered_string);
    //    break;

    //case HTF_WORDWRAP_RIGHT_ALIGNED:
    //    d_formattedRenderedString =
    //        new RenderedStringWordWrapper
    //            <RightAlignedRenderedString>(rendered_string);
    //    break;

    //case HTF_WORDWRAP_JUSTIFIED:
    //    d_formattedRenderedString =
    //        new RenderedStringWordWrapper
    //            <JustifiedRenderedString>(rendered_string);
        //break;
    }
}

void TextComponent::render_impl(Window& srcWindow, hgeRect& destRect, const ColourRect* modColours, const hgeRect* clipper, bool /*clipToDisplay*/) const
{
    // get font to use
    hgeFont* font;

    try
    {
        font = d_fontPropertyName.empty() ?
            (d_font.empty() ? srcWindow.getFont() : &FontManager::getSingleton().getFont(d_font))
            : &FontManager::getSingleton().getFont(srcWindow.getProperty(d_fontPropertyName));
    }
    catch (UnknownObjectException&)
    {
        font = 0;
    }

    // exit if we have no font to use.
    if (!font)
        return;

    const RenderedString* rs = &d_renderedString;
    // do we fetch text from a property
    if (!d_textPropertyName.empty())
    {
        // fetch text & do bi-directional reordering as needed
        String vis = srcWindow.getProperty(d_textPropertyName);
        // parse string using parser from Window.
        d_renderedString =
            srcWindow.getRenderedStringParser().parse(vis, font, modColours);
    }
    // do we use a static text string from the looknfeel
    else if (!getTextVisual().empty())
        // parse string using parser from Window.
        d_renderedString = srcWindow.getRenderedStringParser().
            parse(getTextVisual(), font, modColours);
    // do we have to override the font?
    else if (font != srcWindow.getFont())
        d_renderedString = srcWindow.getRenderedStringParser().
            parse(srcWindow.getTextVisual(), font, modColours);
    // use ready-made RenderedString from the Window itself
    else
        rs = &srcWindow.getRenderedString();

    setupStringFormatter(srcWindow, *rs);
    d_formattedRenderedString->format(destRect.getSize());

    // Get total formatted height.
    const float textHeight = d_formattedRenderedString->getVerticalExtent();

    // handle dest area adjustments for vertical formatting.
    VerticalTextFormatting vertFormatting = d_vertFormatPropertyName.empty() ? d_vertFormatting :
        PropertyHelper::stringToVertTextFormat(srcWindow.getProperty(d_vertFormatPropertyName));

    switch(vertFormatting)
    {
    case VTF_CENTRE_ALIGNED:
        destRect.d_top += (destRect.getHeight() - textHeight) * 0.5f;
        break;

    case VTF_BOTTOM_ALIGNED:
        destRect.d_top = destRect.d_bottom - textHeight;
        break;

    default:
        // default is VTF_TOP_ALIGNED, for which we take no action.
        break;
    }

    // calculate final colours to be used
    ColourRect finalColours;
    initColoursRect(srcWindow, modColours, finalColours);

    // offset the font little down so that it's centered within its own spacing
//        destRect.d_top += (font->getLineSpacing() - font->getFontHeight()) * 0.5f;
    // add geometry for text to the target window.
    d_formattedRenderedString->draw(srcWindow.getGeometryBuffer(),
                                    destRect.getPosition(),
                                    &finalColours, clipper);
}

bool TextComponent::isTextFetchedFromProperty() const
{
    return !d_textPropertyName.empty();
}

const String& TextComponent::getTextPropertySource() const
{
    return d_textPropertyName;
}

void TextComponent::setTextPropertySource(const String& property)
{
    d_textPropertyName = property;
}

bool TextComponent::isFontFetchedFromProperty() const
{
    return !d_fontPropertyName.empty();
}

const String& TextComponent::getFontPropertySource() const
{
    return d_fontPropertyName;
}

void TextComponent::setFontPropertySource(const String& property)
{
    d_fontPropertyName = property;
}

const String& TextComponent::getTextVisual() const
{
    return d_textLogical;
}

